use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

// A type-safe event bus.
pub struct EventManager {
    listeners: Mutex<HashMap<TypeId, Vec<Arc<dyn Fn(&dyn Any) + Send + Sync>>>>,
}

impl EventManager {
    pub fn new() -> Self {
        Self { listeners: Mutex::new(HashMap::new()) }
    }

    /// Subscribes to an event of a specific type `T`.
    pub fn on<T: Any + Send + Sync>(&self, listener: impl Fn(&T) + Send + Sync + 'static) {
        let type_id = TypeId::of::<T>();
        let listener = Arc::new(move |payload: &dyn Any| {
            if let Some(msg) = payload.downcast_ref::<T>() {
                listener(msg);
            }
        });
        self.listeners.lock().unwrap().entry(type_id).or_default().push(listener);
    }

    /// Dispatches an event of type `T`.
    pub fn dispatch<T: Any>(&self, payload: &T) {
        let type_id = TypeId::of::<T>();
        if let Some(listeners) = self.listeners.lock().unwrap().get(&type_id) {
            for listener in listeners {
                listener(payload);
            }
        }
    }
}

// --- Event Payload Definitions ---

use crate::manifest::{ContributeDefinitions, ContributionPointDefinitions};

/// Dispatched when static contributions from a manifest should be processed.
pub struct ProcessContributionsEvent {
    pub contributor_name: String,
    pub contributes: ContributeDefinitions,
    pub contribution_points: ContributionPointDefinitions,
}

/// Dispatched when a plugin dynamically adds contributions at runtime.
pub struct DynamicContributesAddedEvent {
    pub contributor_name: String,
    pub keyword: String,
    pub definitions: Vec<crate::manifest::ContributeDefinition>,
}
